let parse = require("@babel/parser").parse
let generate = require("@babel/generator").default
let traverse = require("@babel/traverse").default
types = require("@babel/types");

let fs = require("fs")
let js_code = fs.readFileSync("input.js", "utf-8")


let ast = parse(js_code)

//准备工作
traverse(ast, {
    ForStatement(path) {
        path.node.body = types.blockStatement([path.node.body]);
    }
})

//1、还原简单else
traverse(ast, {
    IfStatement: {
        exit: function (path) {
            if (path.get("alternate").node && path.get("alternate.body").length && !path.get("alternate.body.0").isIfStatement()) {
                let name = path.get("test").node.left.name;
                let value = path.get("test").node.right.value;

                let consequent = path.get("alternate").node;

                let test = types.binaryExpression("===", types.identifier(name), types.valueToNode(value))
                //console.log(path.scope.getBinding(name).path.parentPath)
                path.scope.getBinding(name).path.parentPath.container[1].body.body.unshift(types.ifStatement(test, consequent))
                path.get("alternate").remove()
            }
        }
    }
})

// 2、还原简单if
traverse(ast, {
    IfStatement: {
        exit: function (path) {
            if (path.get("consequent").node && path.get("consequent.body").length && !path.get("consequent.body.0").isIfStatement()) {
                if (path.get("test.operator").node === "<") {
                    if (path.get("test.right.value").node === 1) {
                        var value = 0
                        var name = path.get("test").node.left.name;
                    } else {
                        let _path = path
                        while (1){
                        if(_path.parentPath.key === "alternate"){
                            var name = _path.parentPath.parentPath.get("test").node.left.name
                            var value = _path.parentPath.parentPath.get("test").node.right.value
                            break
                        }
                            _path = _path.parentPath;
                        }

                    }
                    let consequent = path.get("consequent").node;
                    let test = types.binaryExpression("===", types.identifier(name), types.valueToNode(value))
                    //console.log(path.scope.getBinding(name).path.parentPath)
                    path.scope.getBinding(name).path.parentPath.container[1].body.body.unshift(types.ifStatement(test, consequent))
                    path.get("consequent").remove()
                }
            }
        }
    }
})
//3、删除无用代码
traverse(ast, {
    IfStatement: function (path){
        if (path.get("consequent").node && path.get("consequent.body").length===0) {
            if (!path.get("alternate").node||path.get("alternate.body").length===0) {
                path.remove();
            }
        }
    }
})

// 满满恶意之插桩优化
// traverse(ast, {
//     ExpressionStatement: function (path){
//         let grand_node_path = path.parentPath.parentPath
//         if(grand_node_path && grand_node_path.isIfStatement() && grand_node_path.get("test.left.name").node === "f"){
//             if(path.get('expression.left').node && path.get("expression.left.name").node === "f"){
//                 // path.parentPath.node.body.push(types.ContinueStatement())
//                 path.insertAfter(types.ContinueStatement())
//             }
//         }
//     }
// })

let _f = [
  12,  4, 15,  0, 22, 16, 10, 25,
  26,  5,  1, 23,  6,  8, 13, 14,
   9,  2, 21,  7, 18, 19, 11,  3,
  20, 24, 17
]


let _f_code = []
traverse(ast, {
    ForStatement: function (path){
        for(i of _f){
            path.traverse({
                IfStatement: function (_ifPath){
                    if(_ifPath.get("test.left.name").node === "f" && _ifPath.get("test.right.value").node === i){
                        _f_code.push.apply(_f_code, _ifPath.get("consequent").node.body)
                    }
                }
            })
        }
        path.parentPath.node.body.push.apply(path.parentPath.node.body, _f_code)
        path.remove()
        return 0
    }
})
let decode_code = generate(ast, {minified: false}).code
fs.writeFileSync("output.js", decode_code)